JS - arrow functions

Revision:


Content

Variety of syntaxes available in arrow functions. When to use arrow functions and when not to use Arrow functions and the "this" keyword Parentheses cannot always be omitted. Differences between arrow and regular functions Some more examples of arrow functions


Variety of syntaxes available in arrow functions.

top

1/ no parameters:

if there are no parameters, you can place an empty parentheses before "=>". example: () => 42

In fact, you don't even need the parentheses!example: _ => 42

examples

code:
                    <div>
                        <p class="spec" id="func3"></p>
                        <p class="spec" id="func4"></p>
                    </div>
                    <script>
                        var myfunc3 = () => {  
                            document.getElementById("func3").innerHTML ="This is an arrow function.";     
                        };  
                        var myfunc4 = _ => {  
                            document.getElementById("func4").innerHTML ="This is an aonther arrow function.";     
                        };  
                        myfunc3();  
                        myfunc4();  
                    </script>
                

2/ single parameter:

with these functions, parentheses are optional.example: x => 42 || (x) => 42

Long version:

examples

greet somebody =>

code:
 
                    <p> greet somebody => <span id="arrow"></span></p>
                    <script>
                        const greet = (who) => {
                            return `Hello, ${who}!`;
                        };
                        result = greet('Eddy Merckx'); 
                        document.getElementById("arrow").innerHTML = result;
                    </script>
                

Omitting parenthesis:

examples

greet somebody =>

code:
                    <p>< greet somebody => <span id="arrow3"></span></p>
                    <script>
                        const greet1 = who => {
                            return `Hello, ${who}!`;
                        };
                        result1 = greet1('Paul Van Himst'); 
                        document.getElementById("arrow3").innerHTML = result1;
                    </script>
                

Long version:

examples

double the numbers 4, 5, 2, 6 =>

code:
                    <div>
                        <p class="spec">double the numbers 4, 5, 2, 6 =><span id="arrow2"></span></p>
                    </div>
                    <script>
                        const numbers = [4, 5, 2, 6];
                        const doubled = numbers.map((number) => {
                            return number * 2;
                        });
                        document.getElementById("arrow2").innerHTML = doubled;
                    </script>  
                

3/ multiple parameters:

parentheses are required for these functions. example: (x, y, z) => 42

4/ statements (as opposed to expressions):

with the arrow function, it is important to remember that statements need to have curly braces. Once the curly braces are present, you always need to write "return" as well.

example:

                var feedTheCat = (cat) => {
                    if (cat === 'hungry') {
                        return 'Feed the cat';
                    } else {
                        return 'Do not feed the cat';
                    }
                }
        

5/ “block body”:

if your function is in a block, you must also use the explicit return statement.

example:

        var addValues = (x, y) => {
            return x + y
          }
        

6/ object literals:

if you are returning an object literal, it needs to be wrapped in parentheses. This forces the interpreter to evaluate what is inside the parentheses, and the object literal is returned. example: x =>({ y: x })

MAIN BENEFIT: no binding of "this".

In classic function expressions, the "this" keyword is bound to different values based on the "context" in which it is called. With arrow functions however, this is "lexically" bound. It means that it uses "this" from the code that contains the arrow function.


When to use arrow functions and when not to use

top

when to use

1/ Items in a list. One of the primary usecases for arrow functions in JavaScript is for functions that get applied over and over again to items in a list.

If you have an array of values that you want to transform using a map, an arrow function is ideal. A common example of this is to pull out a particular value of an object.

2/ Promises and promise chains. Another place arrow functions make for cleaner and more intuitive code is in managing asynchronous code.

Promises make it far easier to manage async code. This is an ideal location for an arrow function, especially if your resulting function is stateful, referencing something in your object.

3/ Object transformations Another common and extremely powerful use for arrow functions is to encapsulate object transformations.

These sorts of simple transformations are an ideal and beautiful place to utilize arrow functions.

when not to use

1/ Object methods. When using an arrow function "this" is not bound to anything and it just inherits it from the parent scope, which in many cases is the window.

2/ Callback functions with dynamic context. If you need your context to be dynamic, arrow functions are not the right choice.

3/ When it makes your code less readable.With regular functions, people know what to expect. With arrow functions, it may be hard to decipher what you are looking at straightaway.


Arrow functions and the "this" keyword

top

The most important thing to remember about arrow functions is the way they handle the "this" keyword. In particular, the "this" keyword inside an arrow function doesn't get rebound.

Arrow functions do not have "this". If "this" is accessed, it is taken from the outside.

examples: arrow function and "this" keyword
code:
                    <div class="container">
                        <button class="start-btn">Start Counter</button>
                    </div>
                    <script>
                        const startBtn = document.querySelector(".start-btn");
                        startBtn.addEventListener('click', function() {
                            this.classList.add('counting')
                            let counter = 10;
                            let timer = setInterval(() => {
                                this.textContent = counter 
                                counter -- 
                                if(counter < 0) {
                                    this.textContent = 'THE END!'
                                    this.classList.remove('counting')
                                    clearInterval(timer)
                                }
                            }, 1000) 
                        })
                        
                    </script>
                

examples: error

code:
                   <p style="margin-left:5vw;"><span id="car"></span> </p>
                   <script>
                       const car = {
                           model: 'Fiesta',
                           manufacturer: 'Ford',
                           fullName: () => {
                               return `${this.manufacturer} ${this.model}`
                           }
                       }
                       car.fullName();
                       console.log(car.fullname);
                       document.getElementById("car").innerHTML = car.fullname; 
                   </script>
               


Parentheses cannot always be omitted.

top

If the arrow function "accepts a rest parameter", "destructures the parameter" or "has no parameters", then you have to keep the parentheses.

rest parameter

examples

greet somebody =>

code:
                <p class="spec">greet somebody => <span id="arrow4"></span></p>
                <script>
                    const greetObject = ({ name }) => {
                        return `Hello, ${name}!`;
                    }
                    result2 = greetObject({ name: 'Eric' }); // => 'Hello, Eric!'
                    document.getElementById("arrow4").innerHTML = result2; 
                </script>
            

destructuring parameters

examples

greet somebody =>

code:
                    <p class="spec">greet somebody => <span id="arrow5"></span></p>
                    <script>
                        const greetPeople = (...args) => {
                            return `Hello, ${args.join(' and ')}!`;
                        }
                        result3 = greetPeople('Eric', 'Stan');   // => 'Hello, Eric and Stan!'
                        document.getElementById("arrow5").innerHTML = result3; 
                    </script>
                

no parameters

examples

greet somebody =>

code:
                    <p class="spec">no parameters - greet somebody => <span id="arrow6"></span></p>
                    <script>
                        const sayHello = () => {
                            return 'Hello!';
                        }
                        result4 = sayHello();   // => Hello 
                        document.getElementById("arrow6").innerHTML = result4; 
                    </script>
                

omitting curly braces

examples

greet somebody =>

code:
                    <p><b>greet somebody => <span id="arrow7"></span></p>
                    <script>
                        const greetSomebody = who => `Hello, ${who}!`;
                        result5 = greetSomebody('Eric Geboers');
                        document.getElementById("arrow7").innerHTML = result5; 
                    </script>
                

If the arrow function body contains one statement, you can omit the curly braces and "return" keyword, then the expression will be implicitely returned. The form when the curly braces are omitted is named an inline arrow function. Omitting the curly braces works flawlessly most of the time but with one exception. When returning an object literal, you have to wrap the literal into a pair of parentheses.

examples

greet somebody =>

code:
                    <p class="spec"> greet somebody => <span id="arrow8"></span></p>
                    <script>
                        const greetPerson_a = who => ({message: `Hello, ${who}!`});
                        result6 = greetPerson_a('Stan Abbeloos');
                        console.log(result6);
                        document.getElementById("arrow8").textContent = JSON.stringify(result6); 
                    </script>
                

implicit return

examples

sum => 1 + 2 = ;
implicit return => ;
implict return =>

code:
                    <p class="spec"><b> sum => 1 + 2 = <span id="arrow7A"></span> ; <br>
                    implicit return => <span id="arrow7B"></span> ; <br>
                    implict return => <span id="arrow7C"></span></p>
                    <script>
                        const sumA = (a, b) => a + b;
                        resultC = sumA(1, 2);
                        document.getElementById("arrow7A").innerHTML = resultC;

                        const myFunction = () => 'test';
                        myFunction() //'test'
                        console.log(myFunction());
                        document.getElementById("arrow7B").innerHTML = myFunction();

                        const thisFunction = () => ({ value: 'test' })
                        thisFunction() //{value: 'test'}
                        console.log(thisFunction());
                        document.getElementById("arrow7C").innerHTML = thisFunction().value;
                    </script>
                


Differences between arrow and regular functions

top

P.S. function declaration and function expression are considered to be regular functions.

"this" value

Inside of a regular JavaScript function, "this" value (a.k.a. the execution context) is dynamic, what means that the value of "this" depends on how the function is invoked, i.e.

1/ during a "simple invocation" the value of "this" equals to the global object (or undefined if the function runs in strict mode),
2/ during a "method invocation" the value of "this" is the object owning the method,
3/ during an "indirect invocation" using myFunc.call(thisVal, arg1, ..., argN) or myFunc.apply(thisVal, [arg1, ..., argN]) the value of "this" equals to the first argument,
4/ during a "constructor invocation" using "new" keyword "this" equals to the newly created instance.

"this" value inside of an arrow function always equals "this" value from the outer function. In other words, the arrow function resolves this lexically.

examples: "this" keyword

arrow:

regular:

code:
                    <div>
                        <p style="margin-left:5vw;">arrow: <span id="one"></span></p>
                        <p style="margin-left:5vw;">regular: <span id="two"></span></p>
                    </div>
                    <script>
                        let user = {
                        name: "Alexander",
                        this1:() => {
                            document.getElementById("one").innerHTML = ("Hello " + this.name + " (P.S. no 'this' binding here)");
                        },
                        this2(){       
                            document.getElementById("two").innerHTML =("Welcome to " + this.name + " (P.S. 'this' binding works here)");
                        }  
                        };
                        user.this1();
                        user.this2();
                    </script>
                

examples: "this" keyword.

arrow:

regular:

code:
                    <div>
                        <p style="margin-left:5vw;">arrow: <span id="one_A"></span></p>
                        <p style="margin-left:5vw;">regular: <span id="two_A"></span></p>         
                    </div>
                <script>
                        const car_a = {
                        brand: 'Ford',
                        model: 'Fiesta',
                        start: function() {
                            document.getElementById("two_A").innerHTML = `Started ${this.brand} ${this.model}`;
                        },
                        stop: () => {
                            document.getElementById("one_A").innerHTML = `Stopped ${this.brand} ${this.model}`;
                        }
                        }
                        car_a.start();
                        car_a.stop();
                    </script>
                

constructors

regular function: the regular function can easily construct objects.

arrow function: an arrow function cannot be used as a constructor. Arrow functions do not have a prototype property and they cannot be used with "new".

examples: constructor

arrow:

regular:

regular:

code:
                    <div>
                        <p style="margin-left:5vw;">arrow: <span id="three"></span></p>
                        <p style="margin-left:5vw;">regular: <span id="four"></span></p>
                        <p style="margin-left:5vw;">regular: <span id="four_A"></span></p>
                    </div>
                    <script>
                        let Person = function(name, height) {
                            this.name = name
                            this.height = height
                        }
                        Person.prototype.hello = function() {
                            console.log('Hi, my name is ' + this.name)
                            document.getElementById("four").innerHTML = ("Hi, my name is " + this.name);                            
                        }
                        let alice = new Person('Alice', 1.7)
                        alice.hello() // Hi, my name is Alice       
                        
                        var My_function = new Function("a","b","return a+b")
                        var x = My_function(2,3)
                        document.getElementById("four_A").innerHTML = "The sum is " + x
                    </script>
                

arguments object

regular function: inside the body of a regular function, "arguments" is a special array-like object containing the list of arguments with which the function has been invoked.

arrow function: no "arguments" special keyword is defined inside an arrow function. The "arguments" object is resolved lexically: the arrow function accesses "arguments" from the outer function.

examples: arguments

arrow:

regular:

regular:

code:
                    <div>
                        <p style="margin-left:4vw;">arrow: <span id="five"></span></p>
                        <p style="margin-left:4vw;">regular: <span id="six"></span></p>
                        <p style="margin-left:4vw;">regular: <span id="seven"></span></p>
                    </div>
                    <script>
                        function myFunctionA() {
                            console.log(arguments);
                        }
                        myFunctionA('a', 'b'); // logs { 0: 'a', 1: 'b', length: 2 }
            
                        function myRegularFunction() {
                            const myArrowFunction = () => {
                                console.log(arguments);
                            }
                            myArrowFunction('c', 'd');
                        }
                        myRegularFunction('a', 'b'); // logs { 0: 'a', 1: 'b', length: 2 }
                    </script>
                

implicit return

regular function: "return" expression statement returns the result from a function. If the "return" statement is missing, or there's no expression after "return" statement, the regular function implicitely returns undefined.

arrow function: you can return values from the arrow function the same way as from a regular function, but with one useful exception. If the arrow function contains one expression, and you omit the function's curly braces, then the expression is implicitly returned. These are the "inline arrows function".

examples: implicit return

arrow:

arrow:

code:
                    <div>
                        <p style="margin-left:4vw;">arrow: <span id="eight"></span></p>
                        <p style="margin-left:4vw;">arrow: <span id="eight_A"></span></p>
                    </div>
                    <script>
                        var func = xx => xx * xx;
                        func(10);
                        result = func(10);
                        // concise body syntax, implied "return"
                        document.getElementById("eight").innerHTML = result;
                        var func1 = (xy, z) => { return xy + z; };
                        func1(4, 5);
                        result1 = func1(4, 5)
                        // with block body, explicit "return" needed
                        document.getElementById("eight_A").innerHTML = result1;
                    </script>
                

methods

regular function: the regular functions are the usual way to define methods on classes.

arrow functions: thanks to "Class fields proposal" (at this moment at stage 3) you can use the arrow function as methods inside classes. Now, in contrast with regular functions, the method defined using an arrow binds this lexically to the class instance.

examples: methods

arrow:

arrow:

code:
                    <div>
                        <p style="margin-left:7vw;">arrow: <span id="eleven"></span></p>
                        <p style="margin-left:7vw;">arrow: <span id="eleven_A"></span></p>        
                    </div>
                    <script>
                        'use strict';
                        var obj = { // does not create a new scope
                            i: 10,
                            b: () => console.log(this.i, this),
                            c: function() {
                                console.log(this.i, this);
                            }
                        }
            
                        obj.b(); // prints undefined, Window {...} (or the global object)
                        obj.c(); // prints 10, Object {...}
                        document.getElementById("eleven").innerHTML = obj.b();
                        document.getElementById("eleven_A").innerHTML = obj.c();
                    </script>
                


Some more examples of arrow functions

top
examples

without parantheses: 5 * 2 =

with parantheses: 5 * 2 =

;

code:
            
                <div>
                    <p>without parantheses: 5 * 2 = <span id="arrow9"></span></p>
                    <p>with parantheses: 5 * 2 = <span id="arrow10"></span></p>
                    <p>; <span id="arrow11"></span></p>
                </div>
                <script>
                    const double = x => x*2;
                    resultA = double(5);
                    document.getElementById("arrow9").innerHTML = resultA;
            
                    const doubleB = (x) => x*2;
                    resultB = doubleB(5);
                    document.getElementById("arrow10").innerHTML = resultB;
            
                    var Add = (num1, num2) => {
                        return (num1+num2)
                    }
                    document.getElementById("arrow11").innerHTML = "sum of 10 and 20 is "+ Add(10, 20);
                </script>